package com.gisquest.rdsuse.mysql;

import cn.hutool.core.util.IdUtil;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gisquest.rdsuse.mysql.config.RdsUsageConfig;
import com.gisquest.rdsuse.mysql.mapper.SearchMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@EnableConfigurationProperties({RdsUsageConfig.class})
@EnableScheduling
@Slf4j
public class RdsUseMysqlApplication implements CommandLineRunner {

    @Resource
    private SearchMapper searchMapper;

    @Resource
    private IAddRdsUsageService addRdsUsageService;

    @Resource
    ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Resource
    private RdsUsageConfig usageConfig;

    public static void main(String[] args) {
        SpringApplication.run(RdsUseMysqlApplication.class, args);
    }

    /**
     * 程序入口
     * @param args
     */
    @Override
    public void run(String... args) {
        threadPoolTaskExecutor.setCorePoolSize(usageConfig.getThreadNum());
        if (usageConfig.getMemorySize() > 0) {
            if (usageConfig.getDiskSize() == 0) {
                usageConfig.setDiskSize(1);
            }
        }
        //0、表结构创建
        createTable();
        //1、硬盘占用
        int count = addRdsUsageService.count(new QueryWrapper<>());
        while (count < usageConfig.getDiskSize()) {
            insert();
            count++;
        }
        while (count > usageConfig.getDiskSize() && count > 0) {
            delete();
            count--;
        }

        //2、cpu占用
        for (int i = 0; i < usageConfig.getThreadNum(); i++) {
            threadPoolTaskExecutor.execute(new RdsCpuThread());
        }

        //3、内存占用（初始化数据-占用任务由定时器完成--暂未实现）
        //int memory = usageConfig.getMemorySize();
        int memory = 0;
        if (memory > 0) {
            int size = 1024 * 100;
            //searchMapper.deleteBySql("TRUNCATE add_rds_usage_num");
            List<Map<String, Object>> maps = searchMapper.selectBySql("select count(*) as num from add_rds_usage_num");
            int num = Integer.parseInt(maps.get(0).get("num").toString());
            for (int i = num; i < 100; i++) {
                searchMapper.insertBySql("INSERT INTO add_rds_usage_num (CREATE_TIME)VALUES(NOW())");
            }
            for (int i = num; i < size; i+=100) {
                searchMapper.insertBySql("INSERT INTO add_rds_usage_num (CREATE_TIME) SELECT NOW() FROM add_rds_usage_num LIMIT 100");
            }
        }
    }

    class RdsCpuThread implements Runnable {
        @Override
        @Transactional(rollbackFor = Exception.class)
        public void run() {

            insertAndDel();
        }

        @Transactional(rollbackFor = Exception.class)
         void insertAndDel() {
            try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("img/default.jpeg")) {
                assert inputStream != null;
                BufferedInputStream bis = new BufferedInputStream(inputStream);
                byte[] bytes = new byte[bis.available()];
                bis.read(bytes);
                bis.close();

                int busyTime = usageConfig.getBusyRate();
                if (busyTime < 1) {
                    busyTime = 1;
                }
                if (busyTime > 95) {
                    busyTime = 95;
                }
                int idleTime = 100 - busyTime;
                AtomicLong startTime = new AtomicLong();
                int finalBusyTime = busyTime;
                while (true) {
                    // busy loop
                    startTime.set(System.currentTimeMillis());

                    String id = IdUtil.simpleUUID();
                    searchMapper.insertRds(id, LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME), bytes);
                    //log.info(Thread.currentThread().getName() + "新增");

                    String deleteSql = "delete from add_rds_usage where id = '" + id + "'";
                    searchMapper.deleteBySql(deleteSql);
                    //log.info(Thread.currentThread().getName() + "删除");

                    // idle loop
                    while ((System.currentTimeMillis() - startTime.get()) <= finalBusyTime) {
                        try {
                            Thread.sleep(idleTime);
                        } catch (InterruptedException e) {
                            System.out.println(e);
                        }
                    }

                }
            } catch (IOException e) {
                log.error("文件获取失败！", e);
            }
        }
    }

    private void createTable() {
        String selectSql = "CREATE TABLE IF NOT EXISTS `add_rds_usage` (\n" +
                "  `id` varchar(100) NOT NULL COMMENT '主键',\n" +
                "  `file_data` mediumblob COMMENT '二进制文件',\n" +
                "  `create_time` datetime DEFAULT NULL COMMENT '创建日期',\n" +
                "  PRIMARY KEY (`id`)\n" +
                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
        searchMapper.selectBySql(selectSql);
        log.info(Thread.currentThread().getName() + "创建表结构");
    }

    private void delete(){
        String selectSql = "select * from add_rds_usage limit 1";
        List<Map<String, Object>> maps = searchMapper.selectBySql(selectSql);
        if (!CollectionUtils.isEmpty(maps)) {
            String deleteSql = "delete from add_rds_usage where id = '" + maps.get(0).get("id") + "'";
            searchMapper.deleteBySql(deleteSql);
            //log.info(Thread.currentThread().getName() + "删除");
        }
    }
    private void insert() {
        try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("img/default.jpeg")) {
            assert inputStream != null;
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            byte[] bytes = new byte[bis.available()];
            bis.read(bytes);
            bis.close();
            String id = IdUtil.simpleUUID();
            searchMapper.insertRds(id, LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME), bytes);
            //log.info(Thread.currentThread().getName() + "新增");
        } catch (IOException e) {
            log.error("文件获取失败！", e);
        }
    }
}
